package roles

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"

	"xagent/internal/actor"
	proto "xagent/proto/v1"
)

type RequirementStatus string

const (
	RequirementStatusDraft     RequirementStatus = "DRAFT"
	RequirementStatusReview    RequirementStatus = "REVIEW"
	RequirementStatusApproved  RequirementStatus = "APPROVED"
	RequirementStatusRejected  RequirementStatus = "REJECTED"
	RequirementStatusCompleted RequirementStatus = "COMPLETED"
)

type Requirement struct {
	ID          string
	Title       string
	Description string
	Priority    int
	Status      RequirementStatus
	CreatedAt   time.Time
	UpdatedAt   time.Time
	CreatedBy   string
	AssignedTo  string
	Tags        []string
	Metadata    map[string]interface{}
}

type UserStory struct {
	ID                 string
	Title              string
	Description        string
	AcceptanceCriteria []string
	Priority           int
	Points             int
	Status             string
	RequirementID      string
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

// ProductManager represents a product manager role
type ProductManager struct {
	*actor.BaseActor
	requirements []*Requirement
	userStories  []*UserStory
	priorities   map[string]int
	logger       *logrus.Logger
}

// NewProductManager creates a new product manager
func NewProductManager() *ProductManager {
	baseActor := actor.NewBaseActor(
		"product_manager",
		"ProductManager",
		"Responsible for product vision and requirements",
	)

	pm := &ProductManager{
		BaseActor:    baseActor,
		requirements: make([]*Requirement, 0),
		userStories:  make([]*UserStory, 0),
		priorities:   make(map[string]int),
		logger:       logrus.New(),
	}

	// Register actions
	pm.AddAction(&AnalyzeRequirementAction{pm})
	pm.AddAction(&CreateUserStoryAction{pm})
	pm.AddAction(&PrioritizeRequirementsAction{pm})

	return pm
}

// Action implementations
type AnalyzeRequirementAction struct {
	pm *ProductManager
}

func (a *AnalyzeRequirementAction) Name() string {
	return "analyze_requirement"
}

func (a *AnalyzeRequirementAction) Prerequisites() []string {
	return nil
}

func (a *AnalyzeRequirementAction) Run(ctx context.Context, input interface{}) (*proto.AgentMessage, error) {
	task, ok := input.(*proto.Task)
	if !ok {
		return nil, fmt.Errorf("invalid input type")
	}

	// Think about the requirement
	thought, err := a.pm.Think(ctx, task.Description)
	if err != nil {
		return nil, err
	}

	// Create new requirement
	req := &Requirement{
		ID:          uuid.NewString(),
		Title:       task.Name,
		Description: thought.Content,
		Priority:    1,
		Status:      RequirementStatusDraft,
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
		CreatedBy:   a.pm.GetRole(),
		Tags:        task.Tags,
		Metadata:    make(map[string]interface{}),
	}

	a.pm.requirements = append(a.pm.requirements, req)

	return &proto.AgentMessage{
		Id:   uuid.NewString(),
		Type: proto.MessageType_MESSAGE_TYPE_RESPONSE,
		Content: &proto.AgentMessage_Message{
			Message: fmt.Sprintf("Requirement analyzed and created: %s", req.ID),
		},
		Metadata: map[string]string{
			"requirement_id": req.ID,
			"status":         string(req.Status),
		},
	}, nil
}

type CreateUserStoryAction struct {
	pm *ProductManager
}

func (a *CreateUserStoryAction) Name() string {
	return "create_user_story"
}

func (a *CreateUserStoryAction) Prerequisites() []string {
	return []string{"analyze_requirement"}
}

func (a *CreateUserStoryAction) Run(ctx context.Context, input interface{}) (*proto.AgentMessage, error) {
	task, ok := input.(*proto.Task)
	if !ok {
		return nil, fmt.Errorf("invalid input type")
	}

	// Think about user stories
	thought, err := a.pm.Think(ctx, fmt.Sprintf("Create user stories for: %s", task.Description))
	if err != nil {
		return nil, err
	}

	// Create user story
	story := &UserStory{
		ID:          uuid.NewString(),
		Title:       task.Name,
		Description: thought.Content,
		Priority:    1,
		Status:      "DRAFT",
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
	}

	a.pm.userStories = append(a.pm.userStories, story)

	return &proto.AgentMessage{
		Id:   uuid.NewString(),
		Type: proto.MessageType_MESSAGE_TYPE_RESPONSE,
		Content: &proto.AgentMessage_Message{
			Message: fmt.Sprintf("User story created: %s", story.ID),
		},
		Metadata: map[string]string{
			"user_story_id": story.ID,
			"status":        story.Status,
		},
	}, nil
}

type PrioritizeRequirementsAction struct {
	pm *ProductManager
}

func (a *PrioritizeRequirementsAction) Name() string {
	return "prioritize_requirements"
}

func (a *PrioritizeRequirementsAction) Prerequisites() []string {
	return []string{"analyze_requirement"}
}

func (a *PrioritizeRequirementsAction) Run(ctx context.Context, input interface{}) (*proto.AgentMessage, error) {
	// Think about priorities
	thought, err := a.pm.Think(ctx, "Prioritize current requirements")
	if err != nil {
		return nil, err
	}

	// Update priorities based on thought
	for _, req := range a.pm.requirements {
		// Calculate priority based on thought content
		priority := 1
		if len(thought.Plan) > 0 {
			// If the requirement title appears earlier in the plan, give it higher priority
			for i, step := range thought.Plan {
				if contains(step, req.Title) {
					priority = len(thought.Plan) - i
					break
				}
			}
		}
		a.pm.priorities[req.ID] = priority
	}

	return &proto.AgentMessage{
		Id:   uuid.NewString(),
		Type: proto.MessageType_MESSAGE_TYPE_RESPONSE,
		Content: &proto.AgentMessage_Message{
			Message: fmt.Sprintf("Requirements prioritized based on analysis: %s", thought.Content),
		},
		Metadata: map[string]string{
			"priority_basis": thought.Reasoning,
		},
	}, nil
}

// Helper function to check if a string contains another string
func contains(s, substr string) bool {
	return strings.Contains(strings.ToLower(s), strings.ToLower(substr))
}

// Helper methods
func (pm *ProductManager) GetRequirement(id string) *Requirement {
	for _, req := range pm.requirements {
		if req.ID == id {
			return req
		}
	}
	return nil
}

func (pm *ProductManager) GetUserStory(id string) *UserStory {
	for _, story := range pm.userStories {
		if story.ID == id {
			return story
		}
	}
	return nil
}

func (pm *ProductManager) UpdateRequirementStatus(id string, status RequirementStatus) error {
	req := pm.GetRequirement(id)
	if req == nil {
		return fmt.Errorf("requirement not found: %s", id)
	}

	req.Status = status
	req.UpdatedAt = time.Now()
	return nil
}
